package com.cecurs.bigexcel;


import org.apache.ibatis.cursor.Cursor;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 导出excel工具类
 * Copyright: Copyright (c) 2020 cecurs
 *
 * @ClassName: ExportUtil
 * @Description: 导出excel工具类
 * @version: v1.0.0
 * @author: zhaohaidong
 * @date: 2020/4/2 0002 16:19
 * <p>
 * Modification History:
 * Date         Author          Version            Description
 * ---------------------------------------------------------*
 * 2020/4/2 0002     zhaohaidong           v1.0.0               修改原因
 */
public class ExportUtil {

    /**
     * 标题
     */
    private String[] title;
    /**
     * 属性
     */
    private String[] attribute;
    /**
     * 格式
     */
    private String[] pattern;
    /**
     * 数据字典
     */
    private String[] dictionary;
    /**
     * 导出文件名称
     */
    private String fileName;

    private Class clazz;

    /**
     * 缓存行号，默认100，不能小于100
     * 请合理设置
     */
    private int rowCache;

    /**
     * 分多个excel压缩阈值，默认-1不压缩
     */
    private int zipThreshold;

    private Map<String, ExportDataFormat> formats;

    private List<SXSSFWorkbook> workbookList;

    public ExportUtil model(Class clazz) {
        this.clazz = clazz;
        handleTitleAndAttribute();
        return this;
    }

    public ExportUtil() {
        this( "导出数据" );
    }

    public ExportUtil(String fileName) {
        this( fileName, 100 );

    }

    public ExportUtil(String fileName, int rowCache) {
        this( fileName, rowCache, -1 );
    }

    public ExportUtil(String fileName, int rowCache, int zipThreshold) {
        this.fileName = fileName;
        this.rowCache = rowCache < 100 ? 100 : rowCache;
        this.zipThreshold = zipThreshold;
        workbookList = new ArrayList<SXSSFWorkbook>( 16 );

    }

    private void handleTitleAndAttribute() {
        Field[] fields = clazz.getDeclaredFields();
        formats = new HashMap<String, ExportDataFormat>( 16 );
        for (Field field : fields) {
            field.setAccessible( true );
            if (field.isAnnotationPresent( ExportDataFormat.class )) {
                ExportDataFormat format = field.getAnnotation( ExportDataFormat.class );
                formats.put( field.getName(), format );
            }
        }
        title = new String[formats.size()];
        attribute = new String[formats.size()];
        pattern = new String[formats.size()];
        dictionary = new String[formats.size()];

        Set<String> keys = formats.keySet();
        for (String key : keys) {
            ExportDataFormat format = formats.get( key );
            title[format.order()] = format.name();
            attribute[format.order()] = key;
            pattern[format.order()] = format.pattern();
            dictionary[format.order()] = format.dictionary();
        }
    }

    /**
     * 执行导出
     * String[] title = {"类型", "发表时间", "用户手机号", "用户姓名", "状态", "发表内容"};
     * String[] attribute = {"type","upTime","phone","name","status","content"};
     * List<T> list 数据体
     * String fileName = "体验官留言审核" + DateUtil.getDateString(new Date()) + ".xlsx";
     */

    public void exec(HttpServletRequest request, HttpServletResponse response, SqlExecutor sqlExecutor) throws NoSuchFieldException, IllegalAccessException, ParseException {
        Cursor result = sqlExecutor.getSqlSession().selectCursor( sqlExecutor.getStatement(), sqlExecutor.getParameter() );
        Iterator iter = result.iterator();
        doexec( request, response, iter );
    }

    public void exec(HttpServletRequest request, HttpServletResponse response, List list) throws NoSuchFieldException, IllegalAccessException, ParseException {
        doexec( request, response, list.iterator() );
    }

    public void doexec(HttpServletRequest request, HttpServletResponse response, Iterator iter) throws NoSuchFieldException, IllegalAccessException, ParseException {

        ExcelUtil excelUtil = new ExcelUtil();
        //获取文档
        SXSSFWorkbook workBook = excelUtil.getWorkbook( rowCache );
        workbookList.add( workBook );
        //创建sheet
        SXSSFSheet sheet = excelUtil.createSheet( workBook, "sheet0" );
        excelUtil.fillTitle( sheet, title );

        int n = 0, m = 0;
        while (iter.hasNext()) {
            //创建多个excel文件，打包压缩下载
            if (n == zipThreshold) {
                workBook = excelUtil.getWorkbook( rowCache );
                workbookList.add( workBook );
                //创建sheet
                sheet = excelUtil.createSheet( workBook, "sheet0" );
                excelUtil.fillTitle( sheet, title );
                n = 0;
                m = 0;
            }
            //根据total来创建sheet,每页显示100w条记录
            if (n == 1000000) {
                //创建sheet
                m++;
                sheet = workBook.createSheet( "sheet" + m );
                excelUtil.fillTitle( sheet, title );
                n = 0;
            } else {
                n++;
            }
            Object data = iter.next();
            String[] row = new String[title.length];
            for (int j = 0; j < title.length; j++) {
                Field field = clazz.getDeclaredField( attribute[j] );
                field.setAccessible( true );
                if (field.get( data ) == null) {
                    continue;
                }
                if (!"".equals( pattern[j] )) {
                    SimpleDateFormat sdf = new SimpleDateFormat( pattern[j] );
                    row[j] = sdf.format( field.get( data ) );
                } else if (!"".equals( dictionary[j] )) {
                    JSONObject json = (JSONObject) new JSONParser().parse( dictionary[j] );
                    row[j] = json.get( String.valueOf( field.get( data ) ) ) == null ? String.valueOf( field.get( data ) ) : json.get( String.valueOf( field.get( data ) ) ).toString();
                } else {
                    row[j] = String.valueOf( field.get( data ) );
                }
            }
            excelUtil.fillData( sheet, row );
        }
        FileDownloadUtil.downLoad( request, response, workbookList, zipThreshold, fileName );
    }

}
